home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / iutilasm.asm < prev    next >
Assembly Source File  |  1994-07-27  |  12KB  |  697 lines

  1. ;    Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2. ; This file is part of Aladdin Ghostscript.
  3. ; Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. ; or distributor accepts any responsibility for the consequences of using it,
  5. ; or for whether it serves any particular purpose or works at all, unless he
  6. ; or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. ; License (the "License") for full details.
  8. ; Every copy of Aladdin Ghostscript must include a copy of the License,
  9. ; normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. ; the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. ; under certain conditions described in the License.  Among other things, the
  12. ; License requires that the copyright notice and this notice be preserved on
  13. ; all copies.
  14.  
  15. ; iutilasm.asm
  16. ; Assembly code for Ghostscript interpreter on MS-DOS systems
  17.  
  18.     ifdef    FOR80386
  19.  
  20.     .286c
  21.  
  22.     endif
  23.  
  24. utilasm_TEXT    SEGMENT    WORD PUBLIC 'CODE'
  25.     ASSUME    CS:utilasm_TEXT
  26.  
  27.  
  28.     ifdef    FOR80386
  29.  
  30. ; Macro for 32-bit operand prefix.
  31. OP32    macro
  32.     db    66h
  33.     endm
  34.  
  35.     endif                    ; FOR80386
  36.  
  37. ; Clear a register
  38.  
  39. clear    macro    reg
  40.     xor    reg,reg
  41.     endm
  42.  
  43.  
  44.     ifdef    FOR80386
  45.  
  46. ; Replace the multiply and divide routines in the Turbo C library
  47. ; if we are running on an 80386.
  48.  
  49. ; Macro to swap the halves of a 32-bit register.
  50. ; Unfortunately, masm won't allow a shift instruction with a count of 16,
  51. ; so we have to code it in hex.
  52. swap    macro    regno
  53.       OP32
  54.     db    0c1h,0c0h+regno,16        ; rol regno,16
  55.     endm
  56. regax    equ    0
  57. regcx    equ    1
  58. regdx    equ    2
  59. regbx    equ    3
  60.  
  61.  
  62. ; Multiply (dx,ax) by (cx,bx) to (dx,ax).
  63.     PUBLIC    LXMUL@
  64.     PUBLIC    F_LXMUL@
  65. F_LXMUL@ proc    far
  66. LXMUL@    proc    far
  67.     swap    regdx
  68.     mov    dx,ax
  69.     swap    regcx
  70.     mov    cx,bx
  71.       OP32
  72.     db    0fh,0afh,0d1h            ; imul dx,cx
  73.       OP32
  74.     mov    ax,dx
  75.     swap    regdx
  76.     ret
  77. LXMUL@    endp
  78. F_LXMUL@ endp
  79.  
  80.  
  81. ; Divide two stack operands, leave the result in (dx,ax).
  82.  
  83.     ifdef    DEBUG
  84.  
  85. setup32    macro
  86.     mov    bx,sp
  87.     push    bp
  88.     mov    bp,sp
  89.       OP32
  90.     mov    ax,ss:[bx+4]            ; dividend
  91.     endm
  92.  
  93. ret32    macro    n
  94.     mov    sp,bp
  95.     pop    bp
  96.     ret    n
  97.     endm
  98.  
  99.     else                    ; !DEBUG
  100.  
  101. setup32    macro
  102.     mov    bx,sp
  103.       OP32
  104.     mov    ax,ss:[bx+4]            ; dividend
  105.     endm
  106.  
  107. ret32    macro    n
  108.     ret    n
  109.     endm
  110.  
  111.     endif                    ; (!)DEBUG
  112.  
  113.     PUBLIC    LDIV@, LUDIV@, LMOD@, LUMOD@
  114.     PUBLIC    F_LDIV@, F_LUDIV@, F_LMOD@, F_LUMOD@
  115. F_LDIV@    proc    far
  116. LDIV@    proc    far
  117.     setup32
  118.       OP32
  119.     cwd
  120.       OP32
  121.     idiv    word ptr ss:[bx+8]        ; divisor
  122.       OP32
  123.     mov    dx,ax
  124.     swap    regdx
  125.     ret32    8
  126. LDIV@    endp
  127. F_LDIV@    endp
  128. F_LUDIV@ proc    far
  129. LUDIV@    proc    far
  130.     setup32
  131.       OP32
  132.     xor    dx,dx
  133.       OP32
  134.     div    word ptr ss:[bx+8]        ; divisor
  135.       OP32
  136.     mov    dx,ax
  137.     swap    regdx
  138.     ret32    8
  139. LUDIV@    endp
  140. F_LUDIV@ endp
  141. F_LMOD@    proc    far
  142. LMOD@    proc    far
  143.     setup32
  144.       OP32
  145.     cwd
  146.       OP32
  147.     idiv    word ptr ss:[bx+8]        ; divisor
  148.       OP32
  149.     mov    ax,dx
  150.     swap    regdx
  151.     ret32    8
  152. LMOD@    endp
  153. F_LMOD@    endp
  154. F_LUMOD@ proc    far
  155. LUMOD@    proc    far
  156.     setup32
  157.       OP32
  158.     xor    dx,dx
  159.       OP32
  160.     div    word ptr ss:[bx+8]        ; divisor
  161.       OP32
  162.     mov    ax,dx
  163.     swap    regdx
  164.     ret32    8
  165. LUMOD@    endp
  166. F_LUMOD@ endp
  167.  
  168.     else                    ; !FOR80386
  169.  
  170. ; Replace the divide routines in the Turbo C library,
  171. ; which do the division one bit at a time (!).
  172.  
  173.     PUBLIC    LDIV@, LMOD@, LUDIV@, LUMOD@
  174.     PUBLIC    F_LDIV@, F_LMOD@, F_LUDIV@, F_LUMOD@
  175.  
  176. ; Negate a long on the stack.
  177. negbp    macro    offset
  178.     neg    word ptr [bp+offset+2]        ; high part
  179.     neg    word ptr [bp+offset]        ; low part
  180.     sbb    word ptr [bp+offset+2],0
  181.     endm
  182.  
  183. ; Negate a long in (dx,ax).
  184. negr    macro
  185.     neg    dx
  186.     neg    ax
  187.     sbb    dx,0
  188.     endm
  189.  
  190. ; Divide two unsigned longs on the stack.
  191. ; Leave either the quotient or the remainder in (dx,ax).
  192. ; Operand offsets assume that bp (and only bp) has been pushed.
  193. nlo    equ    6
  194. nhi    equ    8
  195. dlo    equ    10
  196. dhi    equ    12
  197.  
  198. ; We use an offset in bx to distinguish div from mod,
  199. ; and to indicate whether the result should be negated.
  200. odiv    equ    0
  201. omod    equ    2
  202. odivneg    equ    4
  203. omodneg    equ    6
  204. F_LMOD@    proc    far
  205. LMOD@    proc    far
  206.     push    bp
  207.     mov    bp,sp
  208.     mov    bx,omod
  209.             ; Take abs of denominator
  210.     cmp    byte ptr [bp+dhi+1],bh        ; bh = 0
  211.     jge    modpd
  212.     negbp    dlo
  213. modpd:            ; Negate mod if numerator < 0
  214.     cmp    byte ptr [bp+nhi+1],bh        ; bh = 0
  215.     jge    udiv
  216.     mov    bx,omodneg
  217. negnum:    negbp    nlo
  218.     jmp    udiv
  219. LMOD@    endp
  220. F_LMOD@    endp
  221. F_LUMOD@ proc    far
  222. LUMOD@    proc    far
  223.     mov    bx,omod
  224.     jmp    udpush
  225. LUMOD@    endp
  226. F_LUMOD@ endp
  227. F_LDIV@    proc    far
  228. LDIV@    proc    far
  229.     push    bp
  230.     mov    bp,sp
  231.     mov    bx,odiv
  232.             ; Negate quo if num^den < 0
  233.     mov    ax,[bp+nhi]
  234.     xor    ax,[bp+dhi]
  235.     jge    divabs
  236.     mov    bx,odivneg
  237. divabs:            ; Take abs of denominator
  238.     cmp    byte ptr [bp+dhi+1],bh        ; bh = 0
  239.     jge    divpd
  240.     negbp    dlo
  241. divpd:            ; Take abs of numerator
  242.     cmp    byte ptr [bp+nhi+1],bh        ; bh = 0
  243.     jge    udiv
  244.     jmp    negnum
  245. LDIV@    endp
  246. F_LDIV@    endp
  247. F_LUDIV@ proc    far
  248. LUDIV@    proc    far
  249.     mov    bx,odiv
  250. udpush:    push    bp
  251.     mov    bp,sp
  252. udiv:    push    bx                ; odiv, omod, odivneg, omodneg
  253.     mov    ax,[bp+nlo]
  254.     mov    dx,[bp+nhi]
  255.     mov    bx,[bp+dlo]
  256.     mov    cx,[bp+dhi]
  257. ; Now we are dividing dx:ax by cx:bx.
  258. ; Check to see whether this is really a 32/16 division.
  259.     or    cx,cx
  260.     jnz    div2
  261. ; 32/16, check for 16- vs. 32-bit quotient
  262.     cmp    dx,bx
  263.     jae    div1
  264. ; 32/16 with 16-bit quotient, just do it.
  265.     div    bx                ; ax = quo, dx = rem
  266.     pop    bx
  267.     pop    bp
  268.     jmp    cs:xx1[bx]
  269.     even
  270. xx1    dw    offset divx1
  271.     dw    offset modx1
  272.     dw    offset divx1neg
  273.     dw    offset modx1neg
  274. modx1:    mov    ax,dx
  275. divx1:    xor    dx,dx
  276.     ret    8
  277. modx1neg: mov    ax,dx
  278. divx1neg: xor    dx,dx
  279. rneg:    negr
  280.     ret    8
  281. ; 32/16 with 32-bit quotient, do in 2 parts.
  282. div1:    mov    cx,ax                ; save lo num
  283.     mov    ax,dx
  284.     xor    dx,dx
  285.     div    bx                ; ax = hi quo
  286.     xchg    cx,ax                ; save hi quo, get lo num
  287.     div    bx                ; ax = lo quo, dx = rem
  288.     pop    bx
  289.     pop    bp
  290.     jmp    cs:xx1a[bx]
  291.     even
  292. xx1a    dw    offset divx1a
  293.     dw    offset modx1
  294.     dw    offset divx1aneg
  295.     dw    offset modx1neg
  296. divx1a:    mov    dx,cx                ; hi quo
  297.     ret    8
  298. divx1aneg: mov    dx,cx
  299.     jmp    rneg
  300. ; This is really a 32/32 bit division.
  301. ; (Note that the quotient cannot exceed 16 bits.)
  302. ; The following algorithm is taken from pp. 235-240 of Knuth, vol. 2
  303. ; (first edition).
  304. ; Start by normalizing the numerator and denominator.
  305. div2:    or    ch,ch
  306.     jz    div21                ; ch == 0, but cl != 0
  307. ; Do 8 steps all at once.
  308.     mov    bl,bh
  309.     mov    bh,cl
  310.     mov    cl,ch
  311.     xor    ch,ch
  312.     mov    al,ah
  313.     mov    ah,dl
  314.     mov    dl,dh
  315.     xor    dh,dh
  316.     rol    bx,1                ; faster than jmp
  317. div2a:    rcr    bx,1                ; finish previous shift
  318. div21:    shr    dx,1
  319.     rcr    ax,1
  320.     shr    cx,1
  321.     jnz    div2a
  322.     rcr    bx,1
  323. ; Now we can do a 32/16 divide.
  324. div2x:    div    bx                ; ax = quo, dx = rem
  325. ; Multiply by the denominator, and correct the result.
  326.     mov    cx,ax                ; save quotient
  327.     mul    word ptr [bp+dhi]
  328.     mov    bx,ax                ; save lo part of hi product
  329.     mov    ax,cx
  330.     mul    word ptr [bp+dlo]
  331.     add    dx,bx
  332. ; Now cx = trial quotient, (dx,ax) = cx * denominator.
  333.     not    dx
  334.     neg    ax
  335.     cmc
  336.     adc    dx,0                ; double-precision neg
  337.     jc    divz                ; zero quotient
  338.                         ; requires special handling
  339.     add    ax,[bp+nlo]
  340.     adc    dx,[bp+nhi]
  341.     jc    divx
  342. ; Quotient is too large, adjust it.
  343. div3:    dec    cx
  344.     add    ax,[bp+dlo]
  345.     adc    dx,[bp+dhi]
  346.     jnc    div3
  347. ; All done.  (dx,ax) = remainder, cx = lo quotient.
  348. divx:    pop    bx
  349.     pop    bp
  350.     jmp    cs:xx3[bx]
  351.     even
  352. xx3    dw    offset divx3
  353.     dw    offset modx3
  354.     dw    offset divx3neg
  355.     dw    offset modx3neg
  356. divx3:    mov    ax,cx
  357.     xor    dx,dx
  358. modx3:    ret    8
  359. divx3neg: mov    ax,cx
  360.     xor    dx,dx
  361. modx3neg: jmp    rneg
  362. ; Handle zero quotient specially.
  363. divz:    pop    bx
  364.     jmp    cs:xxz[bx]
  365.     even
  366. xxz    dw    offset divxz
  367.     dw    offset modxz
  368.     dw    offset divxz
  369.     dw    offset modxzneg
  370. divxz:    pop    bp
  371.     ret    8
  372. modxzneg: negbp    nlo
  373. modxz:    mov    ax,[bp+nlo]
  374.     mov    dx,[bp+nhi]
  375.     pop    bp
  376.     ret    8
  377. LUDIV@    endp
  378. F_LUDIV@ endp
  379.  
  380.     endif                    ; FOR80386
  381.  
  382.  
  383.     ifdef    NOFPU
  384.  
  385. ; See gsmisc.c for the C version of this code.
  386.  
  387. ; /*
  388. ;  * Floating multiply with fixed result, for avoiding floating point in
  389. ;  * common coordinate transformations.  Assumes IEEE representation,
  390. ;  * 16-bit short, 32-bit long.  Optimized for the case where the first
  391. ;  * operand has no more than 16 mantissa bits, e.g., where it is a user space
  392. ;  * coordinate (which are often integers).
  393. ;  *
  394. ;  * The assembly language version of this code is actually faster than
  395. ;  * the FPU, if the code is compiled with FPU_TYPE=0 (which requires taking
  396. ;  * a trap on every FPU operation).  If there is no FPU, the assembly
  397. ;  * language version of this code is over 10 times as fast as the
  398. ;  * emulated FPU.
  399. ;  */
  400. ; fixed
  401. ; fmul2fixed_(long /*float*/ a, long /*float*/ b)
  402. ; {
  403.  
  404.     PUBLIC    _fmul2fixed_
  405. _fmul2fixed_ proc far
  406.     push    bp
  407.     mov    bp,sp
  408. a    equ    6
  409. alo    equ    a
  410. ahi    equ    a+2
  411. b    equ    10
  412. blo    equ    b
  413. bhi    equ    b+2
  414.     push    si        ; will hold ma
  415.     push    di        ; will hold mb
  416.  
  417. ;     int e = 260 + _fixed_shift - ((
  418. ;         (((uint)(a >> 16)) & 0x7f80) + (((uint)(b >> 16)) & 0x7f80)
  419. ;       ) >> 7);
  420.  
  421.     mov    dx,[bp+ahi]
  422. ; dfmul2fixed enters here
  423. fmf:    mov    cx,260+12
  424.     mov    ax,[bp+bhi]
  425.     and    ax,7f80h
  426.     and    dx,7f80h
  427.     add    ax,dx
  428.     xchg    ah,al        ; ror ax,7 without using cl
  429.     rol    ax,1
  430.     sub    cx,ax
  431.     push    cx        ; e
  432.  
  433. ;     ulong ma = (ushort)(a >> 8) | 0x8000;
  434. ;     ulong mb = (ushort)(b >> 8) | 0x8000;
  435.  
  436.     mov    si,[bp+alo+1]    ; unaligned
  437.     clear    ax
  438.     mov    di,[bp+blo+1]    ; unaligned
  439.     or    si,8000h
  440.     or    di,8000h
  441.  
  442. ;     ulong p1 = ma * (b & 0xff);
  443.  
  444.     mov    al,[bp+blo]
  445.     mul    si
  446.  
  447. ;            (Do this later:)
  448. ;     ulong p = ma * mb;
  449.  
  450. ;     if ( (byte)a )        /* >16 mantissa bits */
  451.  
  452.     cmp    byte ptr [bp+alo],0
  453.     je    mshort
  454.  
  455. ;     {    ulong p2 = (a & 0xff) * mb;
  456. ;         p += ((((uint)(byte)a * (uint)(byte)b) >> 8) + p1 + p2) >> 8;
  457.  
  458.     mov    cx,dx
  459.     mov    bx,ax
  460.     clear    ax
  461.     mov    al,[bp+alo]
  462.     clear    dx
  463.     mov    dl,[bp+blo]
  464.     mul    dx
  465.     mov    dl,ah        ; dx is zero
  466.     add    bx,cx
  467.     adc    cx,0
  468.     clear    ax
  469.     mov    al,[bp+alo]
  470.     mul    di
  471.     add    ax,bx
  472.     adc    dx,cx
  473.  
  474. ;     }
  475.  
  476. mshort:
  477.  
  478. ;     else
  479. ;         p += p1 >> 8;
  480.  
  481.     mov    bl,ah        ; set (cx,bx) = (dx,ax) >> 8
  482.     mov    bh,dl
  483.     clear    cx
  484.     mov    cl,dh
  485.     mov    ax,si
  486.     mul    di
  487.     add    ax,bx
  488.     adc    dx,cx
  489.  
  490. ;     if ( (uint)e < 32 )        /* e = -1 is possible */
  491.  
  492.     pop    cx        ; e
  493.     cmp    cx,16
  494.     jb    shr1
  495.  
  496. ;     else if ( e >= 32 )        /* also detects a=0 or b=0 */
  497.  
  498.     cmp    cx,0
  499.     jl    eneg
  500.     sub    cx,16
  501.     cmp    cx,16
  502.     jge    shr0
  503.     mov    ax,dx
  504.     clear    dx
  505.     shr    ax,cl
  506.     jmp    ex
  507.  
  508. ;         return fixed_0;
  509.  
  510. shr0:    clear    ax
  511.     clear    dx
  512.     jmp    ex
  513.  
  514. ;     else
  515. ;         p <<= -e;
  516.  
  517.     even
  518. eneg:    neg    cx
  519.     shl    dx,cl
  520.     mov    bx,ax
  521.     shl    ax,cl
  522.     rol    bx,cl
  523.     xor    bx,ax
  524.     add    dx,bx
  525.     jmp    ex
  526.  
  527. ;         p >>= e;
  528.  
  529.     even
  530. shr1:    shr    ax,cl
  531.     mov    bx,dx
  532.     shr    dx,cl
  533.     ror    bx,cl
  534.     xor    bx,dx
  535.     add    ax,bx
  536.  
  537. ex:
  538.  
  539. ;     return ((a ^ b) < 0 ? -p : p);
  540.  
  541.     mov    cx,[bp+ahi]
  542.     xor    cx,[bp+bhi]
  543.     jge    pos
  544.     neg    dx
  545.     neg    ax
  546.     sbb    dx,0
  547. pos:
  548.  
  549. ; }
  550.  
  551. retu:    pop    di
  552.     pop    si
  553.     mov    sp,bp
  554.     pop    bp
  555.     ret
  556.  
  557. _fmul2fixed_ ENDP
  558.  
  559. ; The same routine with the first argument a double rather than a float.
  560. ; The argument is split into two pieces to reduce data movement.
  561.  
  562.     PUBLIC    _dfmul2fixed_
  563. _dfmul2fixed_ proc far
  564.     push    bp
  565.     mov    bp,sp
  566. xalo    equ    6
  567. ;b    equ    10
  568. xahi    equ    14
  569.     push    si        ; overlap this below
  570.     push    di        ; ditto
  571.  
  572. ; Shuffle the arguments and then use fmul2fixed.
  573.  
  574. ; Squeeze 3 exponent bits out of the top 35 bits of a.
  575.  
  576.     mov    dx,[bp+xahi+2]
  577.     mov    bx,0c000h
  578.     mov    ax,[bp+xahi]
  579.     and    bx,dx
  580.     mov    cx,[bp+xalo+2]
  581.     and    dx,7ffh        ; get rid of discarded bits
  582.     add    cx,cx        ; faster than shl!
  583.     jz    cz        ; detect common case
  584.     adc    ax,ax        ; faster than rcl!
  585.     adc    dx,dx
  586.     add    cx,cx
  587.     adc    ax,ax
  588.     adc    dx,dx
  589.     add    cx,cx
  590.     adc    ax,ax
  591.     mov    [bp+alo],ax
  592.     adc    dx,dx
  593.     or    dx,bx
  594.     mov    [bp+ahi],dx
  595.     jmp    fmf
  596.     even
  597. cz:    adc    ax,ax
  598.     adc    dx,dx
  599.     add    ax,ax
  600.     adc    dx,dx
  601.     add    ax,ax
  602.     mov    [bp+alo],ax
  603.     adc    dx,dx
  604.     or    dx,bx
  605.     mov    [bp+ahi],dx
  606.     jmp    fmf
  607.  
  608. _dfmul2fixed_ ENDP
  609.  
  610.     endif                    ; NOFPU
  611.  
  612.  
  613. ; Transpose an 8x8 bit matrix.  See gsmisc.c for the algorithm in C.
  614.     PUBLIC    _memflip8x8
  615. _memflip8x8 proc far
  616.     push    ds
  617.     push    si
  618.     push    di
  619.         ; After pushing, the offsets of the parameters are:
  620.         ; byte *inp=10, int line_size=14, byte *outp=16, int dist=20.
  621.     mov    si,sp
  622.     mov    di,ss:[si+14]            ; line_size
  623.     lds    si,ss:[si+10]            ; inp
  624.         ; We assign variables to registers as follows:
  625.         ; ax = AE, bx = BF, cx (or di) = CG, dx = DH.
  626.         ; Load the input data.  Initially we assign
  627.         ; ax = AB, bx = EF, cx (or di) = CD, dx = GH.
  628.     mov    ah,[si]
  629. iload    macro    reg
  630.     add    si,di
  631.     mov    reg,[si]
  632.     endm
  633.     iload    al
  634.     iload    ch
  635.     iload    cl
  636.     iload    bh
  637.     iload    bl
  638.     iload    dh
  639.     iload    dl
  640.         ; Transposition macro, see C code for explanation.
  641. trans    macro    reg1,reg2,shift,mask
  642.     mov    si,reg1
  643.     shr    si,shift
  644.     xor    si,reg2
  645.     and    si,mask
  646.     xor    reg2,si
  647.     shl    si,shift
  648.     xor    reg1,si
  649.     endm
  650.         ; Do 4x4 transpositions
  651.     mov    di,cx            ; we need cl for the shift count
  652.     mov    cl,4
  653.     trans    bx,ax,cl,0f0fh
  654.     trans    dx,di,cl,0f0fh
  655.         ; Swap B/E, D/G
  656.     xchg    al,bh
  657.     mov    cx,di
  658.     xchg    cl,dh
  659.         ; Do 2x2 transpositions
  660.     mov    di,cx                ; need cl again
  661.     mov    cl,2
  662.     trans    di,ax,cl,3333h
  663.     trans    dx,bx,cl,3333h
  664.     mov    cx,di                ; done shifting >1
  665.         ; Do 1x1 transpositions
  666.     trans    bx,ax,1,5555h
  667.     trans    dx,cx,1,5555h
  668.         ; Store result
  669.     mov    si,sp
  670.     mov    di,ss:[si+20]            ; dist
  671.     lds    si,ss:[si+16]            ; outp
  672.     mov    [si],ah
  673. istore    macro    reg
  674.     add    si,di
  675.     mov    [si],reg
  676.     endm
  677.     istore    bh
  678.     istore    ch
  679.     istore    dh
  680.     istore    al
  681.     istore    bl
  682.     istore    cl
  683.     istore    dl
  684.         ; All done
  685.     pop    di
  686.     pop    si
  687.     pop    ds
  688.     ret
  689. _memflip8x8 ENDP
  690.  
  691.  
  692. utilasm_TEXT ENDS
  693.     END
  694.